package com.bruce.tool.pay.alipay.app.back;

import com.alibaba.fastjson.JSON;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.factory.Factory.Payment;
import com.alipay.easysdk.kernel.Config;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.app.models.AlipayTradeAppPayResponse;
import com.bruce.tool.pay.alipay.app.to.AppPayAliTo;
import lombok.extern.slf4j.Slf4j;

/**
 * 预订单信息拼接工具类
 * 0.定义通用化参数
 * 1.完成参数签名
 * 2.完成参数拼接
 *
 * @author Bruce(刘正航)
 */
@Slf4j
public class AliAppPayHelper {

    /**
     * 初始化支付配合着
     */
    public static void init(String appId, String primaryKey, String publicKey, String notifyUrl) {
        // 1. 设置参数（全局只需设置一次）
        Factory.setOptions(getOptions(appId, primaryKey, publicKey, notifyUrl));
    }

    /**
     * 预订单信息拼接
     */
    public static String joinPrePayInfo(AppPayAliTo appPayAliTo) {
        try {
            // 2. 发起API调用（以创建当面付收款二维码为例）
            AlipayTradeAppPayResponse response = Payment.App()
                    // goods_type=0,虚拟商品,不能用花呗,goods_type=1而虚拟商品,可以用花呗
                    .optional("goods_type", appPayAliTo.getGoodsType())
                    // 该笔订单允许的最晚付款时间，逾期将关闭交易。取值范围：1m～15d。m-分钟，h-小时，d-天，1c-当天（1c-当天的情况下，无论交易何时创建，都在0点关闭）。 该参数数值不接受小数点， 如 1.5h，可转换为 90m。
                    // 注：若为空，则默认为15d。
                    .optional("timeout_express", appPayAliTo.getTimeoutExpress())
                    // 公用回传参数，如果请求时传递了该参数，则返回给商户时会回传该参数。支付宝会在异步通知时将该参数原样返回。本参数必须进行 UrlEncode 之后才可以发送给支付宝
                    .optional("passback_params", appPayAliTo.getPassback())
                    .optional("product_code", "QUICK_MSECURITY_PAY")
                    .pay(appPayAliTo.getSubject(), appPayAliTo.getOrderNo(), appPayAliTo.getTotalAmount());
            // 3. 处理响应或异常
            if (ResponseChecker.success(response)) {
                log.info("调用成功");
                return response.body;
            } else {
                log.info("调用失败，原因：" + response.body);
                throw new RuntimeException("未知原因,拼接错误");
            }
        } catch (Exception e) {
            log.error("调用遭遇异常，原因：", e);
            throw new RuntimeException(e.getMessage(), e);
        }
    }

    private static Config getOptions(String appId, String primaryKey, String publicKey, String notifyUrl) {
        Config config = new Config();
        config.protocol = "https";
        config.gatewayHost = "openapi.alipay.com";
        config.signType = "RSA2";

        // <-- 请填写您的AppId，例如：2019091767145019 -->
        config.appId = appId;

        // 为避免私钥随源码泄露，推荐从文件中读取私钥字符串而不是写入源码中
        // <-- 请填写您的应用私钥，例如：MIIEvQIBADANB ... ... -->
        config.merchantPrivateKey = primaryKey;

        //注：证书文件路径支持设置为文件系统中的路径或CLASS_PATH中的路径，优先从文件系统中加载，加载失败后会继续尝试从CLASS_PATH中加载
//        config.merchantCertPath = "<-- 请填写您的应用公钥证书文件路径，例如：/foo/appCertPublicKey_2019051064521003.crt -->";
//        config.alipayCertPath = "<-- 请填写您的支付宝公钥证书文件路径，例如：/foo/alipayCertPublicKey_RSA2.crt -->";
//        config.alipayRootCertPath = "<-- 请填写您的支付宝根证书文件路径，例如：/foo/alipayRootCert.crt -->";

        //注：如果采用非证书模式，则无需赋值上面的三个证书路径，改为赋值如下的支付宝公钥字符串即可
        // <-- 请填写您的支付宝公钥，例如：MIIBIjANBg... -->
        config.alipayPublicKey = publicKey;

        //可设置异步通知接收服务地址（可选）
        config.notifyUrl = notifyUrl;

        //可设置AES密钥，调用AES加解密相关接口时需要（可选）
//        config.encryptKey = "<-- 请填写您的AES密钥，例如：aa4BtZ4tspm2wnXLb1ThQA== -->";

        return config;
    }

    public static void main(String[] args) {
        AliAppPayHelper.init("", "", "", "");
        AppPayAliTo ali = JSON.parseObject("{\n" +
                "\t\"subject\":\"测试支付宝-APP支付\",\n" +
                "\t\"totalAmount\":\"0.01\",\n" +
                "\t\"quitUrl\":\"http://www.baidu.com\",\n" +
                "\t\"returnUrl\":\"http://www.baidu.com\",\n" +
                "\t\"orderNo\":\"12809328138\",\n" +
                "\t\"passbackParams\":\"a=1&b=2\"\n" +
                "}", AppPayAliTo.class);
        System.out.println(AliAppPayHelper.joinPrePayInfo(ali));
    }
}
